﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;

namespace ebclang
{
    internal class Enumerable<T> : IEnumerable<T> where T : IStreamableElement
    {
        private readonly Enumerator<T> _enumerator = new Enumerator<T>();

        public IEnumerator<T> GetEnumerator()
        {
            return _enumerator;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {

            return _enumerator;
        }
    }
    internal class Enumerator<T> : IEnumerator<T> where T : IStreamableElement
    {
        readonly ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
        readonly object _lock = new object();
        private bool _eos;
        readonly AutoResetEvent _mre = new AutoResetEvent(false);

        internal void AddElement(T element)
        {
            _queue.Enqueue(element);
            lock (_lock)
            {
                if (element.StreamEnd)                
                    _eos = true;                
            }
            _mre.Set();
        }

        public void Dispose()
        {

        }
        
        public bool MoveNext()
        {
            start:
            T element;
            if (_eos)
                return false;

            if (_queue.TryPeek(out element))
                return true;

            _mre.WaitOne();
            goto start;
        }

        public void Reset()
        {

        }

        public T Current
        {
            get
            {
                T element;
                if (_queue.TryDequeue(out element))
                    return element;
                throw new Exception("No Element in queue.");
            }
        }

        object IEnumerator.Current
        {
            get { return Current; }
        }
    }
}